package com.akina.matchsystem.websocket;


import com.akina.matchsystem.common.ErrorCode;
import com.akina.matchsystem.exception.BusinessException;
import com.akina.matchsystem.model.domain.Chat;
import com.akina.matchsystem.model.domain.Team;
import com.akina.matchsystem.model.domain.User;
import com.akina.matchsystem.model.dto.MessageDTO;
import com.akina.matchsystem.model.vo.MessageVO;
import com.akina.matchsystem.service.ChatService;
import com.akina.matchsystem.service.TeamService;
import com.akina.matchsystem.service.UserService;
import com.akina.matchsystem.service.UserTeamService;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.CopyOnWriteArraySet;

import static com.akina.matchsystem.contant.UserConstant.USER_LOGIN_STATE;

@Component
@Slf4j
@ServerEndpoint("/webSocketServer/{userId}/{teamId}")
public class WebSocket {
    //Endpoint创建服务端的端点。

    //存放每个客户端对应的websocket对象
    private static CopyOnWriteArraySet<Session> Session = new CopyOnWriteArraySet<>();
    /**
     * 用户的连接信息
     */
    private static Map<String,Session> onlineSession = new ConcurrentHashMap<>();
    /**
     * 队伍的连接信息
     */
    private final static Map<String,ConcurrentHashMap<String,WebSocket>> roomSession = new ConcurrentHashMap<>();


    /**
     * 房间在线人数
     */
    private static int onlineCount =    0 ;

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocket.onlineCount--;
    }


    //与某个客户端的连接对话,需要它来给客户端发送数据,先建立会话
    /**
     * 当前信息
     */
    private Session session;
    private HttpSession httpSession;


    private static ChatService chatService;
    private static UserService userService;

    @Resource
    public void setHeatMapService(ChatService chatService) {
        WebSocket.chatService = chatService;
    }

    @Resource
    public void setHeatMapService(UserService userService) {

        WebSocket.userService = userService;
    }


/*    private Integer userId;
    private Integer teamId;*/
    /**
     * 建立成功调用的方法
     *
     * @param session
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId") String userId, @PathParam(value = "teamId")String teamId, EndpointConfig config){
        try {
            //检查参数是否为空。
            if(StringUtils.isBlank(userId)||StringUtils.isBlank(teamId)){

                throw new BusinessException(ErrorCode.PARAMS_ERROR);
            }
            //通过调用getUserProperties获得 httpsession
            HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
            //User user =(User)httpSession.getAttribute(USER_LOGIN_STATE);
            this.session=session;
            this.httpSession=httpSession;
        /*
            私聊则跳过
            NaN代表私聊
        */
            if(!"NaN".equals(teamId)) {
            //判断队伍，是否为空
            //进入房间流程，如果队伍不存在则创建，存在则进入
            //如果队伍不存在
            if(!roomSession.containsKey(teamId)) {
                ConcurrentHashMap<String, WebSocket> userSession = new ConcurrentHashMap<>(0);
                //onlineSession.put()
                userSession.put(userId, this);
                roomSession.put(teamId, userSession);
            }
            else{//如果队伍存在
                //判断用户是否已经在队伍中
                if(!roomSession.get(teamId).containsKey(userId)){
                    roomSession.get(teamId).put(userId,this);
                    System.out.println("有新用户加入当前队伍！当前在线人数为" + roomSession.get(teamId).size());
                }

            }
            }
            else {
                //把fromId放进去
                onlineSession.put(userId,this.session);
            }
            System.out.println("有新连接加入！当前在线房间为" + roomSession.size());
            //System.out.println("有新连接加入！当前总在线人数为" + onlineSession.size());
            //this.session.getAsyncRemote().sendText("恭喜您成功连接上WebSocket-->当前在线人数为："+webSocketSet.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 关闭连接调用的方法
     */
    @OnClose
    public void onClose(@PathParam("userId") String userId, @PathParam(value = "teamId") String teamId, Session session){

        try {
            //webSocketSet.remove(this);  //从set中删除
            if (!"NaN".equals(teamId)) {
                if (roomSession.containsKey(teamId)) {
                    if (roomSession.get(teamId).size() > 1) {
                        //如果队伍人数大于1,则减去连接
                        roomSession.get(teamId).remove(userId);
                        System.out.println("有一用户退出当前队伍！"+teamId+" 房间人数为" + roomSession.get(teamId).size());
                    } else {

                        roomSession.remove(teamId);
                        System.out.println("有一房间关闭！当前在线房间数为" + roomSession.size());
                    }
                }
            }
            else {
                //移除toId
                onlineSession.remove(userId);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(@PathParam("userId")String userId,@PathParam("teamId")String teamId,String message,Session session){
        
        
        try {
            if (!"NaN".equals(teamId)) {//群聊逻辑：
                if (roomSession.containsKey(teamId)) {
                    for (WebSocket user : roomSession.get(teamId).values()) {
                        if (!user.session.getId().equals(session.getId())) {//用户相同就不发送消息了
                            user.session.getAsyncRemote().sendText(message);//异步发送消息
                            //this.session.getBasicRemote().sendText(message); //同步     这个是会阻塞的，而异步发送是不会阻塞的
                        }
                    }

                    System.out.println("来自客户端的消息:" + message);
                    Gson gson = new Gson();
                    MessageVO messageVO = gson.fromJson(message, MessageVO.class);
                    if (messageVO != null) {//聊天存入数据库。

                        Chat chat = new Chat();
                        chat.setContent(messageVO.getContent());
                        chat.setFromId(messageVO.getFromId());
                        //chat.setCreateTime(date);
                        chat.setTeamId((long) Integer.parseInt(teamId));
                        chat.setChatType(2);
                        chatService.saveMessage(chat);

                    }
                }
                //群发消息
                //broadcast(message);
            }
            else {//私聊 在线就发送实时消息，否则就存入数据库

                //User fromUser = (User)this.httpSession.getAttribute(USER_LOGIN_STATE);

                //onlineSession.get(userId).session.getAsyncRemote().sendText(message);//toId用户接受消息

                //User fromUser = userService.getById(userId);
                //从Message里取出toId。
                Gson gson = new Gson();
                MessageVO messageVO = gson.fromJson(message, MessageVO.class);
                Long fromId = messageVO.getFromId();
                Long toId = messageVO.getToId();
                String toIdStr = toId.toString();
                //检测对方连接了没
                if(onlineSession.containsKey(toIdStr)) {
                    onlineSession.get(toIdStr).getAsyncRemote().sendText(message);
                    //存储消息记录
                    System.out.println("来自客户端的消息:" + message);
                }
                //if (messageVO != null) {//聊天存入数据库。

                    Chat chat = new Chat();
                    chat.setContent(messageVO.getContent());
                    chat.setToId(messageVO.getToId());//这里的fromId其实是toId就不改字段名了
                    chat.setFromId(fromId);
                    //chat.setCreateTime(date);
                    //chat.setTeamId((long) Integer.parseInt(teamId));
                    chat.setChatType(1);//私聊
                    chatService.saveMessage(chat);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 群发信息
     */
    public void broadcast(String message){
        for(ConcurrentHashMap<String,WebSocket> item:roomSession.values()){//集合里的每一个对象
            for( WebSocket user : item.values()) {
                user.session.getAsyncRemote().sendText(message);//异步发送消息
                //this.session.getBasicRemote().sendText(message); //同步     这个是会阻塞的，而异步发送是不会阻塞的
            }
        }
    }



    /*    *//**
     * 发生错误时调用
     * @param session
     *//*
    @OnError
    public void onErroe(Session session){

    }*/
/*
    */
/**
     * 发送失败
     *
     * @param userId       用户id
     * @param errorMessage 错误消息
     *//*

    private void sendError(String userId, String errorMessage) {
        //JSONObject obj = new JSONObject();
        obj.set("error", errorMessage);
        //sendOneMessage(userId, obj.toString());
    }
*/

}
